home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 45
/
Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso
/
Aminet
/
gfx
/
x11
/
x3270_3_2_16.lha
/
amiga_src
/
save.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-23
|
16KB
|
740 lines
/*
* Copyright 1994, 1995, 1999, 2000 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*/
/*
* save.c
* Implements the response to the WM_SAVE_YOURSELF message and
* x3270 profiles.
*/
#include "globals.h"
#include <X11/StringDefs.h>
#include <X11/Xatom.h>
#include <pwd.h>
#include <errno.h>
#include <time.h>
#include "appres.h"
#include "resources.h"
#include "savec.h"
#include "popupsc.h"
#include "utilc.h"
/* Support for WM_SAVE_YOURSELF. */
extern Boolean keypad_changed;
extern Boolean keypad_popped;
extern Boolean model_changed;
extern Boolean scrollbar_changed;
extern Boolean efont_changed;
extern Boolean oversize_changed;
extern Boolean scheme_changed;
extern Boolean keymap_changed;
extern Boolean charset_changed;
char *command_string = CN;
static char *cmd;
static int cmd_len;
#define NWORDS 1024
static char **tmp_cmd;
static int tcs;
static Status x_get_window_attributes(Window w, XWindowAttributes *wa);
/* Search for an option in the tmp_cmd array. */
static int
cmd_srch(const char *s)
{
int i;
for (i = 1; i < tcs; i++)
if (tmp_cmd[i] && !strcmp(tmp_cmd[i], s))
return i;
return 0;
}
/* Replace an options in the tmp_cmd array. */
static void
cmd_replace(int ix, const char *s)
{
XtFree(tmp_cmd[ix]);
tmp_cmd[ix] = XtNewString(s);
}
/* Append an option to the tmp_cmd array. */
static void
cmd_append(const char *s)
{
tmp_cmd[tcs++] = XtNewString(s);
tmp_cmd[tcs] = (char *) NULL;
}
/* Delete an option from the tmp_cmd array. */
static void
cmd_delete(int ix)
{
XtFree(tmp_cmd[ix]);
tmp_cmd[ix] = (char *) NULL;
}
/* Save the screen geometry. */
static void
save_xy(void)
{
char tbuf[64];
Window window, frame, child;
XWindowAttributes wa;
int x, y;
int ix;
window = XtWindow(toplevel);
if (!x_get_window_attributes(window, &wa))
return;
(void) XTranslateCoordinates(display, window, wa.root,
-wa.border_width, -wa.border_width,
&x, &y, &child);
frame = XtWindow(toplevel);
while (True) {
Window root, parent;
Window *wchildren;
unsigned int nchildren;
int status = XQueryTree(display, frame, &root, &parent,
&wchildren, &nchildren);
if (status && wchildren)
XFree((char *)wchildren);
if (parent == root || !parent || !status)
break;
frame = parent;
}
if (frame != window) {
if (!x_get_window_attributes(frame, &wa))
return;
x = wa.x;
y = wa.y;
}
(void) sprintf(tbuf, "+%d+%d", x, y);
if ((ix = cmd_srch("-geometry")))
cmd_replace(ix + 1, tbuf);
else {
cmd_append("-geometry");
cmd_append(tbuf);
}
}
/* Save the icon information: state, label, geometry. */
static void
save_icon(void)
{
unsigned char *data;
int iconX, iconY;
char tbuf[64];
int ix;
unsigned long nitems;
{
Atom actual_type;
int actual_format;
unsigned long leftover;
if (XGetWindowProperty(display, XtWindow(toplevel), a_state,
0L, 2L, False, a_state, &actual_type, &actual_format,
&nitems, &leftover, &data) != Success)
return;
if (actual_type != a_state ||
actual_format != 32 ||
nitems < 1)
return;
}
ix = cmd_srch("-iconic");
if (*(unsigned long *)data == IconicState) {
if (!ix)
cmd_append("-iconic");
} else {
if (ix)
cmd_delete(ix);
}
if (nitems < 2)
return;
{
Window icon_window;
XWindowAttributes wa;
Window child;
icon_window = *(Window *)(data + sizeof(unsigned long));
if (icon_window == None)
return;
if (!x_get_window_attributes(icon_window, &wa))
return;
(void) XTranslateCoordinates(display, icon_window, wa.root,
-wa.border_width, -wa.border_width, &iconX, &iconY,
&child);
if (!iconX && !iconY)
return;
}
(void) sprintf(tbuf, "%d", iconX);
ix = cmd_srch(OptIconX);
if (ix)
cmd_replace(ix + 1, tbuf);
else {
cmd_append(OptIconX);
cmd_append(tbuf);
}
(void) sprintf(tbuf, "%d", iconY);
ix = cmd_srch(OptIconY);
if (ix)
cmd_replace(ix + 1, tbuf);
else {
cmd_append(OptIconY);
cmd_append(tbuf);
}
return;
}
/* Save the keymap information. */
static void
save_keymap(void)
{
/* Note: keymap propogation is deliberately disabled, because it
may vary from workstation to workstation. The recommended
way of specifying keymaps is through your .Xdefaults or the
KEYMAP or KEYBD environment variables, which can be easily set
in your .login or .profile to machine-specific values; the
-keymap switch is really for debugging or testing keymaps.
I'm sure I'll regret this. */
#if defined(notdef) /*[*/
if (appres.keymap) {
add_string(v, OptKeymap);
add_string(v, appres.keymap);
}
#endif /*]*/
}
/* Save the model name. */
static void
save_model(void)
{
int ix;
if (!model_changed)
return;
if ((ix = cmd_srch(OptModel)) && strcmp(tmp_cmd[ix], model_name))
cmd_replace(ix + 1, model_name);
else {
cmd_append(OptModel);
cmd_append(model_name);
}
}
/* Save the emulator font. */
static void
save_efont(void)
{
int ix;
if (!efont_changed)
return;
if ((ix = cmd_srch(OptEmulatorFont)) && strcmp(tmp_cmd[ix], efontname))
cmd_replace(ix + 1, efontname);
else {
cmd_append(OptEmulatorFont);
cmd_append(efontname);
}
}
#if defined(X3270_KEYPAD) /*[*/
/* Save the keypad state. */
static void
save_keypad(void)
{
int ix;
ix = cmd_srch(OptKeypadOn);
if (appres.keypad_on || keypad_popped) {
if (!ix)
cmd_append(OptKeypadOn);
} else {
if (ix)
cmd_delete(ix);
}
}
#endif /*]*/
/* Save the scrollbar state. */
static void
save_scrollbar(void)
{
int i_on, i_off;
if (!scrollbar_changed)
return;
i_on = cmd_srch(OptScrollBar);
i_off = cmd_srch(OptNoScrollBar);
if (toggled(SCROLL_BAR)) {
if (!i_on) {
if (i_off)
cmd_replace(i_off, OptScrollBar);
else
cmd_append(OptScrollBar);
}
} else {
if (!i_off) {
if (i_on)
cmd_replace(i_on, OptNoScrollBar);
else
cmd_append(OptNoScrollBar);
}
}
}
/* Save the name of the host we are connected to. */
static void
save_host(void)
{
char *space;
if (!CONNECTED)
return;
space = strchr(full_current_host, ' ');
if (space == (char *) NULL)
cmd_append(full_current_host);
else {
char *tmp = XtNewString(full_current_host);
char *port;
space = strchr(tmp, ' ');
*space = '\0';
cmd_append(tmp);
port = space + 1;
while (*port == ' ')
port++;
if (*port)
cmd_append(port);
XtFree(tmp);
}
}
/* Save the settings of each of the toggles. */
static void
save_toggles(void)
{
int i, j;
int ix;
for (i = 0; i < N_TOGGLES; i++) {
if (!appres.toggle[i].changed)
continue;
/*
* Find the last "-set" or "-clear" for this toggle.
* If there is a preferred alias, delete them instead.
*/
ix = 0;
for (j = 1; j < tcs; j++)
if (tmp_cmd[j] &&
(!strcmp(tmp_cmd[j], OptSet) ||
!strcmp(tmp_cmd[j], OptClear)) &&
tmp_cmd[j+1] &&
!strcmp(tmp_cmd[j+1], toggle_names[i].name)) {
if (i == SCROLL_BAR
#if defined(X3270_TRACE) /*[*/
|| i == DS_TRACE
#endif /*]*/
) {
cmd_delete(j);
cmd_delete(j + 1);
} else
ix = j;
}
/* Handle aliased switches. */
switch (i) {
case SCROLL_BAR:
continue; /* +sb/-sb done separately */
#if defined(X3270_TRACE) /*[*/
case DS_TRACE:
ix = cmd_srch(OptDsTrace);
if (appres.toggle[DS_TRACE].value) {
if (!ix)
cmd_append(OptDsTrace);
} else {
if (ix)
cmd_delete(ix);
}
continue;
#endif /*]*/
}
/* If need be, switch "-set" with "-clear", or append one. */
if (appres.toggle[i].value) {
if (ix && strcmp(tmp_cmd[ix], OptSet))
cmd_replace(ix, OptSet);
else if (!ix) {
cmd_append(OptSet);
cmd_append(toggle_names[i].name);
}
} else {
if (ix && strcmp(tmp_cmd[ix], OptClear))
cmd_replace(ix, OptClear);
else if (!ix) {
cmd_append(OptClear);
cmd_append(toggle_names[i].name);
}
}
}
}
/* Remove a positional parameter from the command line. */
static void
remove_positional(char *s)
{
char *c;
c = cmd + cmd_len - 2; /* last byte of last arg */
while (*c && c >= cmd)
c--;
if (strcmp(s, c + 1))
XtError("Command-line switches must precede positional arguments");
cmd_len = c - cmd;
}
/* Save a copy of he XA_WM_COMMAND poperty. */
void
save_init(int argc, char *hostname, char *port)
{
Atom actual_type;
int actual_format;
unsigned long nitems;
unsigned long bytes_after;
/*
* Fetch the initial value of the XA_COMMAND property and store
* it in 'cmd'.
*/
XGetWindowProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
0L, 1000000L, False, XA_STRING, &actual_type, &actual_format,
&nitems, &bytes_after, (unsigned char **)&cmd);
if (nitems == 0)
XtError("Could not get initial XA_COMMAND property");
cmd_len = nitems * (actual_format / 8);
/*
* Now locate the hostname and port positional arguments, and
* remove them. If they aren't the last two components of the
* command line, abort.
*/
switch (argc) {
case 3:
remove_positional(port);
/* fall through */
case 2:
remove_positional(hostname);
break;
}
}
/* Handle a WM_SAVE_YOURSELF ICCM. */
void
save_yourself(void)
{
int i;
char *c, *c2;
int len;
if (command_string != CN) {
XtFree(command_string);
command_string = CN;
}
/* Copy the original command line into tmp_cmd. */
tmp_cmd = (char **) XtMalloc(sizeof(char *) * NWORDS);
tcs = 0;
i = 0;
c = cmd;
while (i < cmd_len) {
c = cmd + i;
tmp_cmd[tcs++] = XtNewString(c);
i += strlen(c);
i++;
}
tmp_cmd[tcs] = (char *) NULL;
/* Replace the first element with the program name. */
cmd_replace(0, programname);
/* Save options. */
save_xy();
save_icon();
save_keymap();
save_model();
save_efont();
#if defined(X3270_KEYPAD) /*[*/
save_keypad();
#endif /*]*/
save_scrollbar();
save_toggles();
save_host();
/* Copy what's left into contiguous memory. */
len = 0;
for (i = 0; i < tcs; i++)
if (tmp_cmd[i])
len += strlen(tmp_cmd[i]) + 1;
c = XtMalloc(len);
c[0] = '\0';
c2 = c;
for (i = 0; i < tcs; i++)
if (tmp_cmd[i]) {
(void) strcpy(c2, tmp_cmd[i]);
c2 += strlen(c2) + 1;
XtFree(tmp_cmd[i]);
}
XtFree((XtPointer)tmp_cmd);
/* Change the property. */
XChangeProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
XA_STRING, 8, PropModeReplace, (unsigned char *)c, len);
/* Save a readable copy of the command string for posterity. */
command_string = c;
while (((c2 = strchr(c, '\0')) != CN) &&
(c2 - command_string < len-1)) {
*c2 = ' ';
c = c2 + 1;
}
}
/* Support for x3270 profiles. */
#define PROFILE_ENV "X3270PRO"
#define NO_PROFILE_ENV "NOX3270PRO"
#define DEFAULT_PROFILE "~/.x3270pro"
extern XrmOptionDescRec options[];
extern int num_options;
char *profile_name = CN;
static char *xcmd;
static int xargc;
static char **xargv;
#if defined(X3270_MENUS) /*[*/
/* Save one option in the file. */
static void
save_opt(FILE *f, const char *full_name, const char *opt_name,
const char *res_name, const char *value)
{
(void) fprintf(f, "! %s (%s)\nx3270.%s: %s\n",
full_name, opt_name, res_name, value);
}
/* Save the current options settings in a profile. */
int
save_options(char *n)
{
FILE *f;
Boolean exists = False;
char *ct;
int i;
time_t clk;
char buf[64];
Boolean any_toggles = False;
if (n == CN || *n == '\0')
return -1;
/* Open the file. */
n = do_subst(n, True, True);
f = fopen(n, "r");
if (f != (FILE *)NULL) {
(void) fclose(f);
exists = True;
}
f = fopen(n, "a");
if (f == (FILE *)NULL) {
popup_an_errno(errno, "Cannot open %s", n);
XtFree(n);
return -1;
}
/* Save the name. */
if (profile_name == CN)
XtFree(profile_name);
profile_name = n;
/* Print the header. */
clk = time((time_t *)0);
ct = ctime(&clk);
if (ct[strlen(ct)-1] == '\n')
ct[strlen(ct)-1] = '\0';
if (exists)
(void) fprintf(f, "! File updated %s by %s\n", ct, build);
else
(void) fprintf(f,
"! x3270 profile\n\
! File created %s by %s\n\
! This file overrides xrdb and .Xdefaults.\n\
! To skip reading this file, set %s in the environment.\n\
!\n",
ct, build, NO_PROFILE_ENV);
/* Save most of the toggles. */
for (i = 0; i < N_TOGGLES; i++) {
if (!appres.toggle[i].changed)
continue;
#if defined(X3270_TRACE) /*[*/
if (i == DS_TRACE || i == SCREEN_TRACE || i == EVENT_TRACE)
continue;
#endif /*]*/
if (!any_toggles) {
(void) fprintf(f, "! toggles (%s, %s)\n",
OptSet, OptClear);
any_toggles = True;
}
(void) fprintf(f, "x3270.%s: %s\n", toggle_names[i].name,
appres.toggle[i].value ? ResTrue : ResFalse);
}
#if defined(X3270_KEYPAD) /*[*/
/* Save the keypad state. */
if (keypad_changed)
save_opt(f, "keypad state", OptKeypadOn, ResKeypadOn,
(appres.keypad_on || keypad_popped) ?
ResTrue : ResFalse);
#endif /*]*/
/* Save other menu-changeable options. */
if (efont_changed)
save_opt(f, "emulator font", OptEmulatorFont, ResEmulatorFont,
efontname);
if (model_changed) {
(void) sprintf(buf, "%d", model_num);
save_opt(f, "model", OptModel, ResModel, buf);
}
if (oversize_changed) {
(void) sprintf(buf, "%dx%d", ov_cols, ov_rows);
save_opt(f, "oversize", OptOversize, ResOversize, buf);
}
if (scheme_changed && appres.color_scheme != CN)
save_opt(f, "color scheme", OptColorScheme, ResColorScheme,
appres.color_scheme);
if (keymap_changed && appres.key_map != (char *)NULL)
save_opt(f, "keymap", OptKeymap, ResKeymap, appres.key_map);
if (charset_changed && appres.charset != (char *)NULL)
save_opt(f, "charset", OptCharset, ResCharset, appres.charset);
/* Done. */
(void) fclose(f);
return 0;
}
#endif /*]*/
/* Save a copy of the command-line options. */
void
save_args(int argc, char *argv[])
{
int i;
int len = 0;
for (i = 0; i < argc; i++)
len += strlen(argv[i]) + 1;
xcmd = XtMalloc(len + 1);
xargv = (char **)XtMalloc((argc + 1) * sizeof(char *));
len = 0;
for (i = 0; i < argc; i++) {
xargv[i] = xcmd + len;
(void) strcpy(xcmd + len, argv[i]);
len += strlen(argv[i]) + 1;
}
xargv[i] = CN;
*(xcmd + len) = '\0';
xargc = argc;
}
/* Merge in the options settings from a profile. */
void
merge_profile(XrmDatabase *d)
{
const char *fname;
XrmDatabase dd;
/* Open the file. */
if (getenv(NO_PROFILE_ENV) != CN) {
profile_name = do_subst(DEFAULT_PROFILE, True, True);
return;
}
fname = getenv(PROFILE_ENV);
if (fname == CN || *fname == '\0')
fname = DEFAULT_PROFILE;
profile_name = do_subst(fname, True, True);
/* Create a resource database from the file. */
dd = XrmGetFileDatabase(profile_name);
if (dd == NULL)
goto done;
/* Merge in the profile options. */
XrmMergeDatabases(dd, d);
/* Merge the saved command-line options back on top of those. */
dd = NULL;
XrmParseCommand(&dd, options, num_options, programname, &xargc, xargv);
XrmMergeDatabases(dd, d);
done:
/* Free the saved command-line options. */
XtFree(xcmd);
xcmd = CN;
XtFree((char *)xargv);
xargv = (char **)NULL;
}
/*
* Safe routine for querying window attributes
*/
static int
dummy_error_handler(Display *d unused, XErrorEvent *e unused)
{
return 0;
}
static Status
x_get_window_attributes(Window w, XWindowAttributes *wa)
{
XErrorHandler old_handler;
Status s;
old_handler = XSetErrorHandler(dummy_error_handler);
s = XGetWindowAttributes(display, w, wa);
if (!s)
(void) fprintf(stderr, "Error: querying bad window 0x%lx\n", w);
(void) XSetErrorHandler(old_handler);
return s;
}